#include <unistd.h>
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <math.h>

#include <ev.h>

static struct ev_loop *p_loop = NULL;
static int right_answer = -1;
static int remain_question_number = 5;

static ev_timer _30sec_event;
static ev_timer _20sec_event;
static ev_timer _10sec_event;
static ev_io stdin_read_event;

static void AskQuestion();
static void On30SecCallback(struct ev_loop *, ev_timer *, int);
static void On20SecCallback(struct ev_loop *, ev_timer *, int);
static void On10SecCallback(struct ev_loop *, ev_timer *, int);
static void OnStdinReadCallback(struct ev_loop *, ev_io *, int);

static void InitTimerEvent(ev_timer *p_w, void(*cb)(struct ev_loop*, ev_timer*, int), double at, double repeat)
{
    p_w->active = p_w->pending = 0;
    p_w->priority = 0;
    p_w->cb = cb;
    p_w->data = NULL;
    p_w->repeat = repeat;
    p_w->at = at;
}

static void InitFdEvent(ev_io *p_w, void(*cb)(struct ev_loop*, ev_io*, int), int fd, int events)
{
    p_w->active = p_w->pending = 0;
    p_w->priority = 0;
    p_w->cb = cb;
    p_w->data = NULL;
    p_w->fd = fd;
    p_w->events = events | EV__IOFDSET;
}

void Game_Init(struct ev_loop *p_loop_)
{
    p_loop = p_loop_;
    InitTimerEvent(&_30sec_event, On30SecCallback, 30, 0);
    InitTimerEvent(&_20sec_event, On20SecCallback, 20, 0);
    InitTimerEvent(&_10sec_event, On10SecCallback, 10, 0);
    InitFdEvent(&stdin_read_event, OnStdinReadCallback, STDIN_FILENO, EV_READ);

    puts("Welcome to Calculate Gate.");
    puts("You need answer 5 questions in 30 seconds. Each question has only 10 second.");
    puts("Here we go!");

    srand(time(NULL));
    ev_timer_start(p_loop, &_30sec_event);
    ev_timer_start(p_loop, &_20sec_event);
    ev_io_start(p_loop, &stdin_read_event);

    AskQuestion();
}

void Game_Cleanup()
{
    ev_timer_stop(p_loop, &_30sec_event);
    ev_timer_stop(p_loop, &_20sec_event);
    ev_timer_stop(p_loop, &_10sec_event);
    ev_io_stop(p_loop, &stdin_read_event);
}

static void AskQuestion()
{
    ev_timer_stop(p_loop, &_10sec_event);

    int a = random() % 100;
    int b = random() % 100;
    right_answer = a + b;
    printf("%d + %d = ? \nyour answer: ", a, b);
    fflush(stdout);

    --remain_question_number;

    ev_timer_start(p_loop, &_10sec_event);
}

static void On30SecCallback(struct ev_loop *p_loop, ev_timer *p_w, int events)
{
    puts("\ntime is up, you fail!");
    ev_break(p_loop, EVBREAK_ALL);
}

static void On20SecCallback(struct ev_loop *p_loop, ev_timer *p_w, int events)
{
    puts("\n10 sec remain...");
}

static void On10SecCallback(struct ev_loop *p_loop, ev_timer *p_w, int events)
{
    puts("\ntimeout. You fail!");
    ev_break(p_loop, EVBREAK_ALL);
}

static void OnStdinReadCallback(struct ev_loop *p_loop, ev_io *p_w, int events)
{
    char input_buff[200];
    int rsize = read(STDIN_FILENO, input_buff, sizeof(input_buff));
    input_buff[rsize - 1];

    int answer = atoi(input_buff);
    if (answer == right_answer) {
        if (remain_question_number == 0) {
            puts("Congratulation! You win.");
            ev_break(p_loop, EVBREAK_ALL);
        } else {
            AskQuestion();
        }
    } else {
        puts("wrong answer. You fail.");
        ev_break(p_loop, EVBREAK_ALL);
    }
}
